home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / ftpcli.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  15KB  |  690 lines

  1. /* FTP client (interactive user) code */
  2. #define    LINELEN        128    /* Length of command buffer */
  3. #include <stdio.h>
  4. #ifdef __TURBOC__
  5. #include "fcntl.h"
  6. #endif
  7. #include "global.h"
  8. #include "config.h"
  9. #include "mbuf.h"
  10. #include "netuser.h"
  11. #include "icmp.h"
  12. #include "timer.h"
  13. #include "tcp.h"
  14. #include "ftp.h"
  15. #include "session.h"
  16. #include "cmdparse.h"
  17. #include "telnet.h"
  18. #include "iface.h"
  19. #include "ax25.h"
  20. #include "lapb.h"
  21. #include "finger.h"
  22. #include "nr4.h"
  23. #ifdef    BSD
  24. char *sprintf();
  25. #endif
  26.  
  27. /* #ifdef __TURBOC__    */
  28. /* #include <fcntl.h>    */
  29. /* #endif        */
  30.  
  31. extern struct session *current;
  32. extern char nospace[];
  33. extern char badhost[];
  34. static char notsess[] = "Not an FTP session!\n";
  35. static char cantwrite[] = "Can't write %s\n";
  36. static char cantread[] = "Can't read %s\n";
  37.  
  38. int donothing(),doftpcd(),dolist(),doget(),dols(),doput(),dotype(),doabort(),
  39.     domkdir(),dormdir();
  40.  
  41. struct cmds ftpabort[] = {
  42.     "",        donothing,    0,    NULLCHAR,        NULLCHAR,
  43.     "abort",    doabort,    0,    NULLCHAR,        NULLCHAR,
  44.     NULLCHAR,    NULLFP,        0,    "Only valid command is \"abort\"", NULLCHAR,
  45. };
  46.  
  47. struct cmds ftpcmds[] = {
  48.     "",        donothing,    0,    NULLCHAR,        NULLCHAR,
  49.     "cd",        doftpcd,    2,    "cd <directory>",    NULLCHAR,
  50.     "dir",        dolist,        0,    NULLCHAR,        NULLCHAR,
  51.     "list",        dolist,        0,    NULLCHAR,        NULLCHAR,
  52.     "get",        doget,        2,    "get remotefile <localfile>",    NULLCHAR,
  53.     "ls",        dols,        0,    NULLCHAR,        NULLCHAR,
  54.     "mkdir",    domkdir,    2,    "mkdir <directory>",    NULLCHAR,
  55.     "nlst",        dols,        0,    NULLCHAR,        NULLCHAR,
  56.     "rmdir",    dormdir,    2,    "rmdir <directory>",    NULLCHAR,
  57.     "put",        doput,        2,    "put localfile <remotefile>",    NULLCHAR,
  58.     "type",        dotype,        0,    NULLCHAR,        NULLCHAR,
  59.     NULLCHAR,    NULLFP,        0,     NULLCHAR,        NULLCHAR,
  60. };
  61.  
  62. /* Handle top-level FTP command */
  63. doftp(argc,argv)
  64. int argc;
  65. char *argv[];
  66. {
  67.     int32 resolve();
  68.     int ftpparse();
  69.     char *inet_ntoa();
  70.     void ftpccr(),ftpccs();
  71.     struct session *s;
  72.     struct ftp *ftp,*ftp_create();
  73.     struct tcb *tcb;
  74.     struct socket lsocket,fsocket;
  75.  
  76.     lsocket.address = ip_addr;
  77.     lsocket.port = lport++;
  78.     if((fsocket.address = resolve(argv[1])) == 0){
  79.         printf(badhost,argv[1]);
  80.         return 1;
  81.     }
  82.     if(argc < 3)
  83.         fsocket.port = FTP_PORT;
  84.     else
  85.         fsocket.port = atoi(argv[2]);
  86.  
  87.     /* Allocate a session control block */
  88.     if((s = newsession()) == NULLSESSION){
  89.         printf("Too many sessions\n");
  90.         return 1;
  91.     }
  92.     current = s;
  93.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  94.         strcpy(s->name,argv[1]);
  95.     s->type = FTP;
  96.     s->parse = ftpparse;
  97.  
  98.     /* Allocate an FTP control block */
  99.     if((ftp = ftp_create(LINELEN)) == NULLFTP){
  100.         s->type = FREE;
  101.         printf(nospace);
  102.         return 1;
  103.     }
  104.     ftp->state = STARTUP_STATE;
  105.     s->cb.ftp = ftp;    /* Downward link */
  106.     ftp->session = s;    /* Upward link */
  107.  
  108.     /* Now open the control connection */
  109.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,
  110.         0,ftpccr,NULLVFP,ftpccs,0,(char *)ftp);
  111.     ftp->control = tcb;
  112.     go();
  113.     return 0;
  114. }
  115. /* Parse user FTP commands */
  116. int
  117. ftpparse(line,len)
  118. char *line;
  119. int16 len;
  120. {
  121.     struct mbuf *bp;
  122.  
  123.     switch(current->cb.ftp->state){
  124.     case RECEIVING_STATE:
  125.     case SENDING_STATE:
  126.         /* The only command allowed in data transfer state is ABORT */
  127.         if(cmdparse(ftpabort,line) == -1){
  128.             printf("Transfer in progress; only ABORT is acceptable\n");
  129.         }
  130.         fflush(stdout);
  131.         break;
  132.     case COMMAND_STATE:
  133.         /* Save it now because cmdparse modifies the original */
  134.         bp = qdata(line,len);
  135.  
  136.         if(cmdparse(ftpcmds,line) == -1){
  137.             /* Send it direct */
  138.             if(bp != NULLBUF)
  139.                 send_tcp(current->cb.ftp->control,bp);
  140.             else
  141.                 printf(nospace);
  142.         } else {
  143.             free_p(bp);
  144.         }
  145.         fflush(stdout);
  146.         break;
  147.     case STARTUP_STATE:        /* Starting up autologin */
  148.         printf("Not connected yet, ignoring %s\r\n",line);
  149.         break;
  150.     case USER_STATE:        /* Got the user name */
  151.         line[len] = '\0';
  152.         return sndftpmsg(current->cb.ftp,"USER %s",line);
  153.     case PASS_STATE:        /* Got the password */
  154.         cooked();
  155.         line[len] = '\0';
  156.         return sndftpmsg(current->cb.ftp,"PASS %s",line);
  157.     }
  158.     return 0;
  159. }
  160. /* Handle null line to avoid trapping on first command in table */
  161. /*ARGSUSED*/
  162. static
  163. int
  164. donothing(argc,argv)
  165. int argc;
  166. char *argv[];
  167. {
  168. }
  169. /* Translate 'cd' to 'cwd' for convenience */
  170. /*ARGSUSED*/
  171. static
  172. int
  173. doftpcd(argc,argv)
  174. int argc;
  175. char *argv[];
  176. {
  177.     register struct ftp *ftp;
  178.  
  179.     ftp = current->cb.ftp;
  180.     return sndftpmsg(ftp,"CWD %s\r\n",argv[1]);
  181. }
  182. /* Translate 'mkdir' to 'xmkd' for convenience */
  183. /*ARGSUSED*/
  184. static
  185. int
  186. domkdir(argc,argv)
  187. int argc;
  188. char *argv[];
  189. {
  190.     register struct ftp *ftp;
  191.  
  192.     ftp = current->cb.ftp;
  193.     return sndftpmsg(ftp,"XMKD %s\r\n",argv[1]);
  194. }
  195. /* Translate 'rmdir' to 'xrmd' for convenience */
  196. /*ARGSUSED*/
  197. static
  198. int
  199. dormdir(argc,argv)
  200. int argc;
  201. char *argv[];
  202. {
  203.     register struct ftp *ftp;
  204.  
  205.     ftp = current->cb.ftp;
  206.     return sndftpmsg(ftp,"XRMD %s\r\n",argv[1]);
  207. }
  208. /* Handle "type" command from user */
  209. static
  210. int
  211. dotype(argc,argv)
  212. int argc;
  213. char *argv[];
  214. {
  215.     register struct ftp *ftp;
  216.  
  217.     ftp = current->cb.ftp;
  218.     if(argc < 2){
  219.         switch(ftp->type){
  220.         case IMAGE_TYPE:
  221.             printf("Image\n");
  222.             break;
  223.         case ASCII_TYPE:
  224.             printf("Ascii\n");
  225.             break;
  226.         }
  227.         return 0;
  228.     }
  229.     switch(*argv[1]){
  230.     case 'i':
  231.     case 'b':
  232.         ftp->type = IMAGE_TYPE;
  233.         sndftpmsg(ftp,"TYPE I\r\n");
  234.         break;
  235.     case 'a':
  236.         ftp->type = ASCII_TYPE;
  237.         sndftpmsg(ftp,"TYPE A\r\n");
  238.         break;
  239.     case 'l':
  240.         ftp->type = IMAGE_TYPE;
  241.         sndftpmsg(ftp,"TYPE L %s\r\n",argv[2]);
  242.         break;
  243.     default:
  244.         printf("Invalid type %s\n",argv[1]);
  245.         return 1;
  246.     }
  247.     return 0;
  248. }
  249. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  250. static
  251. doget(argc,argv)
  252. int argc;
  253. char *argv[];
  254. {
  255.     void ftpdr(),ftpcds();
  256.     char *remotename,*localname;
  257.     register struct ftp *ftp;
  258.     char *mode;
  259.  
  260.     ftp = current->cb.ftp;
  261.     if(ftp == NULLFTP){
  262.         printf(notsess);
  263.         return 1;
  264.     }
  265.     remotename = argv[1];
  266.     if(argc < 3)
  267.         localname = remotename;
  268.     else
  269.         localname = argv[2];
  270.  
  271.     if(ftp->fp != NULLFILE && ftp->fp != stdout)
  272.         fclose(ftp->fp);
  273.     ftp->fp = NULLFILE;
  274.  
  275.     if(ftp->type == IMAGE_TYPE) 
  276.         mode = binmode[WRITE_BINARY];
  277.     else
  278.         mode = "w";
  279.  
  280.     if((ftp->fp = fopen(localname,mode)) == NULLFILE){
  281.         printf(cantwrite,localname);
  282.         return 1;
  283.     }
  284.     ftp->state = RECEIVING_STATE;
  285.     ftpsetup(ftp,ftpdr,NULLVFP,ftpcds);
  286.  
  287.     /* Generate the command to start the transfer */
  288.     return sndftpmsg(ftp,"RETR %s\r\n",remotename);
  289. }
  290. /* List remote directory. Syntax: dir <remote directory/file> [<local name>] */
  291. static
  292. dolist(argc,argv)
  293. int argc;
  294. char *argv[];
  295. {
  296.     void ftpdr(),ftpcds();
  297.     register struct ftp *ftp;
  298.  
  299.     ftp = current->cb.ftp;
  300.     if(ftp == NULLFTP){
  301.         printf(notsess);
  302.         return 1;
  303.     }
  304.     if(ftp->fp != NULLFILE && ftp->fp != stdout)
  305.         fclose(ftp->fp);
  306.     ftp->fp = NULLFILE;
  307.  
  308.     if(argc < 3){
  309.         ftp->fp = stdout;
  310.     } else if((ftp->fp = fopen(argv[2],"w")) == NULLFILE){
  311.         printf(cantwrite,argv[2]);
  312.         return 1;
  313.     }
  314.     ftp->state = RECEIVING_STATE;
  315.     ftpsetup(ftp,ftpdr,NULLVFP,ftpcds);
  316.     /* Generate the command to start the transfer
  317.      * It's done this way to avoid confusing the 4.2 FTP server
  318.      * if there's no argument
  319.      */
  320.     if(argc > 1)
  321.         return sndftpmsg(ftp,"LIST %s\r\n",argv[1]);
  322.     else
  323.         return sndftpmsg(ftp,"LIST\r\n","");
  324. }
  325. /* Abbreviated (name only) list of remote directory.
  326.  * Syntax: ls <remote directory/file> [<local name>]
  327.  */
  328. static
  329. dols(argc,argv)
  330. int argc;
  331. char *argv[];
  332. {
  333.     void ftpdr(),ftpcds();
  334.     register struct ftp *ftp;
  335.  
  336.     ftp = current->cb.ftp;
  337.     if(ftp == NULLFTP){
  338.         printf(notsess);
  339.         return 1;
  340.     }
  341.     if(ftp->fp != NULLFILE && ftp->fp != stdout)
  342.         fclose(ftp->fp);
  343.     ftp->fp = NULLFILE;
  344.  
  345.     if(argc < 3){
  346.         ftp->fp = stdout;
  347.     } else if((ftp->fp = fopen(argv[2],"w")) == NULLFILE){
  348.         printf(cantwrite,argv[2]);
  349.         return 1;
  350.     }
  351.     ftp->state = RECEIVING_STATE;
  352.     ftpsetup(ftp,ftpdr,NULLVFP,ftpcds);
  353.     /* Generate the command to start the transfer */
  354.     if(argc > 1)
  355.         return sndftpmsg(ftp,"NLST %s\r\n",argv[1]);
  356.     else
  357.         return sndftpmsg(ftp,"NLST\r\n","");
  358. }
  359. /* Start transmit. Syntax: put <local name> [<remote name>] */
  360. static
  361. doput(argc,argv)
  362. int argc;
  363. char *argv[];
  364. {
  365.     void ftpdt(),ftpcds();
  366.     char *remotename,*localname;
  367.     char *mode;
  368.     struct ftp *ftp;
  369.  
  370.     if((ftp = current->cb.ftp) == NULLFTP){
  371.         printf(notsess);
  372.         return 1;
  373.     }
  374.     localname = argv[1];
  375.     if(argc < 3)
  376.         remotename = localname;
  377.     else
  378.         remotename = argv[2];
  379.  
  380.     if(ftp->fp != NULLFILE && ftp->fp != stdout)
  381.         fclose(ftp->fp);
  382.  
  383.     if(ftp->type == IMAGE_TYPE) 
  384.         mode = binmode[READ_BINARY];
  385.     else
  386.         mode = "r";
  387.  
  388.     if((ftp->fp = fopen(localname,mode)) == NULLFILE){
  389.         printf(cantread,localname);
  390.         return 1;
  391.     }
  392.     ftp->state = SENDING_STATE;
  393.     ftpsetup(ftp,NULLVFP,ftpdt,ftpcds);
  394.  
  395.     /* Generate the command to start the transfer */
  396.     return sndftpmsg(ftp,"STOR %s\r\n",remotename);
  397. }
  398. /* Abort a GET or PUT operation in progress. Note: this will leave
  399.  * the partial file on the local or remote system
  400.  */
  401. /*ARGSUSED*/
  402. doabort(argc,argv)
  403. int argc;
  404. char *argv[];
  405. {
  406.     register struct ftp *ftp;
  407.  
  408.     ftp = current->cb.ftp;
  409.  
  410.     /* Close the local file */
  411.     if(ftp->fp != NULLFILE && ftp->fp != stdout)
  412.         fclose(ftp->fp);
  413.     ftp->fp = NULLFILE;
  414.  
  415.     switch(ftp->state){
  416.     case SENDING_STATE:
  417.         /* Send a premature EOF.
  418.          * Unfortunately we can't just reset the connection
  419.          * since the remote side might end up waiting forever
  420.          * for us to send something.
  421.          */
  422.         close_tcp(ftp->data);
  423.         printf("Put aborted\n");
  424.         break;
  425.     case RECEIVING_STATE:
  426.         /* Just exterminate the data channel TCB; this will
  427.          * generate a RST on the next data packet which will
  428.          * abort the sender
  429.          */
  430.         del_tcp(ftp->data);
  431.         ftp->data = NULLTCB;
  432.         printf("Get aborted\n");
  433.         break;
  434.     }
  435.     ftp->state = COMMAND_STATE;
  436.     fflush(stdout);
  437. }
  438. /* create data port, and send PORT message */
  439. static
  440. ftpsetup(ftp,recv,send,state)
  441. struct ftp *ftp;
  442. void (*send)();
  443. void (*recv)();
  444. void (*state)();
  445. {
  446.     struct socket lsocket;
  447.     struct mbuf *bp;
  448.  
  449.     lsocket.address = ip_addr;
  450.     lsocket.port = lport++;
  451.  
  452.     /* Compose and send PORT a,a,a,a,p,p message */
  453.  
  454.     if((bp = alloc_mbuf(35)) == NULLBUF){    /* 5 more than worst case */
  455.         printf(nospace);
  456.         return;
  457.     }
  458.     /* I know, this looks gross, but it works! */
  459.     sprintf(bp->data,"PORT %u,%u,%u,%u,%u,%u\r\n",
  460.         hibyte(hiword(lsocket.address)),
  461.         lobyte(hiword(lsocket.address)),
  462.         hibyte(loword(lsocket.address)),
  463.         lobyte(loword(lsocket.address)),
  464.         hibyte(lsocket.port),
  465.         lobyte(lsocket.port));
  466.     bp->cnt = strlen(bp->data);
  467.     send_tcp(ftp->control,bp);
  468.  
  469.     /* Post a listen on the data connection */
  470.     ftp->data = open_tcp(&lsocket,NULLSOCK,TCP_PASSIVE,0,
  471.         recv,send,state,0,(char *)ftp);
  472. }
  473. /* FTP Client Control channel Receiver upcall routine */
  474. void
  475. ftpccr(tcb,cnt)
  476. register struct tcb *tcb;
  477. int16 cnt;
  478. {
  479.     struct mbuf *bp;
  480.     struct ftp *ftp;
  481.     void doreply();
  482.     char c;
  483.  
  484.     if((ftp = (struct ftp *)tcb->user) == NULLFTP){
  485.         /* Unknown connection; kill it */
  486.         close_tcp(tcb);
  487.         return;
  488.     }
  489.     /* Hold output if we're not the current session */
  490.     if(mode != CONV_MODE || current == NULLSESSION || current->cb.ftp != ftp)
  491.         return;
  492.  
  493.     if(recv_tcp(tcb,&bp,cnt) > 0){
  494.         while(pullup(&bp,&c,1) == 1){
  495.             switch(c){
  496.             case '\r':    /* Strip cr's */
  497.                 continue;
  498.             case '\n':    /* Complete line; process it */
  499.                 ftp->buf[ftp->cnt] = '\0';
  500.                 doreply(ftp);
  501.                 ftp->cnt = 0;
  502.                 break;
  503.             default:    /* Assemble line */
  504.                 if(ftp->cnt != LINELEN-1)
  505.                     ftp->buf[ftp->cnt++] = c;
  506.                 break;
  507.             }
  508.         }
  509.         fflush(stdout);
  510.     }
  511. }
  512.  
  513.  
  514. /* Process replies from the server */
  515. static
  516. void
  517. doreply(ftp)
  518. register struct ftp *ftp;
  519. {
  520.     void echo(), noecho();
  521.     static char crlf[]="\n";
  522.  
  523.     fwrite(ftp->buf,1,(unsigned)ftp->cnt,stdout);
  524.     fputc('\n', stdout);
  525.     if (ftp->cnt < 3) return;
  526.     ftp->buf[3] = '\0';
  527.     switch(ftp->state){
  528.     case SENDING_STATE:
  529.     case RECEIVING_STATE:
  530.         if (ftp->buf[0] == '5') doabort(0,(char *)0);
  531.         break;
  532.     case STARTUP_STATE:
  533.         if (!strcmp(ftp->buf, "220")){
  534.             ftp->state = USER_STATE;
  535.             printf("Enter user name: ");
  536.             fflush(stdout);
  537.         } else ftp->state = COMMAND_STATE;
  538.         break;
  539.     case COMMAND_STATE:
  540.     case USER_STATE:
  541.         if (!strcmp(ftp->buf, "331")) {
  542.             ftp->state = PASS_STATE;
  543.             noecho();
  544.             printf("Password: ");
  545.             fflush(stdout);
  546.         } else ftp->state = COMMAND_STATE;
  547.         break;
  548.     case PASS_STATE:
  549.         echo();
  550.         ftp->state = COMMAND_STATE;
  551.         break;
  552.     }
  553. }
  554.  
  555. /* FTP Client Control channel State change upcall routine */
  556. /*ARGSUSED*/
  557. static
  558. void
  559. ftpccs(tcb,old,new)
  560. register struct tcb *tcb;
  561. char old,new;
  562. {
  563.     void ftp_delete();
  564.     struct ftp *ftp;
  565.     char notify = 0;
  566.     extern char *tcpstates[];
  567.     extern char *reasons[];
  568.     extern char *unreach[];
  569.     extern char *exceed[];
  570.  
  571.     /* Can't add a check for unknown connection here, it would loop
  572.      * on a close upcall! We're just careful later on.
  573.      */
  574.     ftp = (struct ftp *)tcb->user;
  575.  
  576.     if(current != NULLSESSION && current->cb.ftp == ftp)
  577.         notify = 1;
  578.  
  579.     switch(new){
  580.     case CLOSE_WAIT:
  581.         if(notify)
  582.             printf("%s\n",tcpstates[new]);
  583.         close_tcp(tcb);
  584.         break;
  585.     case CLOSED:    /* heh heh */
  586.         if(notify){
  587.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  588.             if(tcb->reason == NETWORK){
  589.                 switch(tcb->type){
  590.                 case DEST_UNREACH:
  591.                     printf(": %s unreachable",unreach[tcb->code]);
  592.                     break;
  593.                 case TIME_EXCEED:
  594.                     printf(": %s time exceeded",exceed[tcb->code]);
  595.                     break;
  596.                 }
  597.             }
  598.             printf(")\n");
  599.             cmdmode();
  600.         }
  601.         del_tcp(tcb);
  602.         if(ftp != NULLFTP)
  603.             ftp_delete(ftp);
  604.         break;
  605.     default:
  606.         if(notify)
  607.             printf("%s\n",tcpstates[new]);
  608.         break;
  609.     }
  610.     if(notify)
  611.         fflush(stdout);
  612. }
  613. /* FTP Client Data channel State change upcall handler */
  614. /*ARGSUSED*/
  615. static
  616. void
  617. ftpcds(tcb,old,new)
  618. struct tcb *tcb;
  619. char old,new;
  620. {
  621.     struct ftp *ftp;
  622.  
  623.     if((ftp = (struct ftp *)tcb->user) == NULLFTP){
  624.         /* Unknown connection, kill it */
  625.         close_tcp(tcb);
  626.         return;
  627.     }
  628.     switch(new){
  629.     case FINWAIT2:
  630.     case TIME_WAIT:
  631.         if(ftp->state == SENDING_STATE){
  632.             /* We've received an ack of our FIN, so
  633.              * return to command mode
  634.              */
  635.             ftp->state = COMMAND_STATE;
  636.             if(current != NULLSESSION && current->cb.ftp == ftp){
  637.                 printf("Put complete, %lu bytes sent\n",
  638.                     tcb->snd.una - tcb->iss - 2);
  639.                 fflush(stdout);
  640.             }
  641.         }
  642.         break;        
  643.     case CLOSE_WAIT:
  644.         close_tcp(tcb);
  645.         if(ftp->state == RECEIVING_STATE){
  646.             /* End of file received on incoming file */
  647. #ifdef    CPM
  648.             if(ftp->type == ASCII_TYPE)
  649.                 putc(CTLZ,ftp->fp);
  650. #endif
  651.             if(ftp->fp != stdout)
  652.                 fclose(ftp->fp);
  653.             ftp->fp = NULLFILE;
  654.             ftp->state = COMMAND_STATE;
  655.             if(current != NULLSESSION && current->cb.ftp == ftp){
  656.                 printf("Get complete, %lu bytes received\n",
  657.                     tcb->rcv.nxt - tcb->irs - 2);
  658.                 fflush(stdout);
  659.             }
  660.         }
  661.         break;
  662.     case CLOSED:
  663.         ftp->data = NULLTCB;
  664.         del_tcp(tcb);
  665.         break;
  666.     }
  667. }
  668. /* Send a message on the control channel */
  669. /*VARARGS*/
  670. static
  671. int
  672. sndftpmsg(ftp,fmt,arg)
  673. struct ftp *ftp;
  674. char *fmt;
  675. char *arg;
  676. {
  677.     struct mbuf *bp;
  678.     int16 len;
  679.  
  680.     len = strlen(fmt) + strlen(arg) + 10;    /* fudge factor */
  681.     if((bp = alloc_mbuf(len)) == NULLBUF){
  682.         printf(nospace);
  683.         return 1;
  684.     }
  685.     sprintf(bp->data,fmt,arg);
  686.     bp->cnt = strlen(bp->data);
  687.     send_tcp(ftp->control,bp);
  688.     return 0;
  689. }
  690.